/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package trunk.model;

import java.awt.Color;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import trunk.observer.Observable;
import trunk.observer.Observer;

/**
 * Class PaintModel 
 * 
 * Model général
 * 
 * @author LEFEVRE Michael
 * @author THOUE Jonathan
 */
public class PaintModel implements Observable,Serializable{

    private Dessin dessin;
    private ArrayList<Observer> listObserver = new ArrayList<Observer>();
    
    
    /**
     * Constructeur par defaut de PaintModel
     */
    public PaintModel() {
        dessin = new Dessin();
    }

    /**
     * Methode pour supprimer la dernier forme géometrique créer
     */
    public void annuler(){
        this.dessin.getElements().remove(dessin.getElements().size()-1);
        notifyObserver(dessin);
    }
    /**
     * Réinitialise le dessin
     */
    public void reset() {
        dessin.getElements().clear();
        notifyObserver(dessin);
    }
    /**
     * Retire la selection des formes
     */
    public void resetSelection() {
        for (ElementGeo element : dessin.getElements()) {
            element.setSelected(false);
        }
        notifyObserver(dessin); 
    }
     /**
     * Selectionne tout les formes
     */
    public void selectAll() {
        for (ElementGeo element : dessin.getElements()) {
            element.setSelected(true);
        }
        notifyObserver(dessin); 
    }
    /**
     * Ajouter une formes geometrique au dessin
     */
    public void addElement(ElementGeo element) {
        dessin.getElements().add(element);
        notifyObserver(dessin); 
    }
    /**
     * Supprime une formes geometrique au dessin
     */
    public void eraseElement(ElementGeo element){
        dessin.getElements().remove(element);
        notifyObserver(dessin); 
    }
    public void cloneElement(){
        List<ElementGeo> listDuplicateElem = new ArrayList<ElementGeo>();
           for(ElementGeo elementSelected : dessin.getElements()){
                    if(elementSelected.isSelected()){
                        listDuplicateElem.add(elementSelected);
                        elementSelected.setSelected(false);
                    }
                }
           if (!listDuplicateElem.isEmpty()){
                for (ElementGeo duplicateElement : listDuplicateElem){
                      ElementGeo clone = duplicateElement.createClone();
                      clone.setCouleur(duplicateElement.getCouleur());
                      dessin.getElements().add(clone);
                      clone.translateTo(50, 50);
                      clone.setSelected(true);
                }
           }
           notifyObserver(dessin);
    }
    /**
     * Change la couleur courrante
     */
    public void setColor(Color color) {
        dessin.setCurrentColor(color);
        notifyObserver(dessin); 
    }
    /**
     * Ajoute une couleur à la palette
     */
    public void addColor(Color color){
        dessin.getPalette().add(color);
        notifyObserver(dessin);
    }
    /**
     * Change l'outils courant
     */
    public void setTool(EDrawTool tool) {
        dessin.setCurrentTool(tool);
        notifyObserver(dessin); 
    }
    /**
     * Change le titre du dessin
     */
    public void setTitle(String title) {
        dessin.setName(title);
        notifyObserver(dessin); 
    }
    /**
     * Change le pas de la grille
     */
    public void setPas(int pas) {
        dessin.setPasGrid(pas);
        notifyObserver(dessin); 
    }
    /**
     * Change l'origine du dessin
     */
    public void setOrigine(Point o){
        dessin.setOrigine(o);
        notifyObserver(dessin);
    }
    /**
     * Applique la symetrie par rapport à l'origine à tout les éléments selectionnés
     */
    public void symetrieO(){        
        for (ElementGeo element : dessin.getElements()) {
            if(element.isSelected())
            element.symetrieO(dessin.getOrigine());
        }
        notifyObserver(dessin);
    }
    /**
     * Applique la symetrie par rapport à X à tout les éléments selectionnés
     */
    public void symetrieX(){        
        for (ElementGeo element : dessin.getElements()) {
            if(element.isSelected())
            element.symetrieX(dessin.getOrigine());
        }
        notifyObserver(dessin);
    }
    /**
     * Applique la symetrie par rapport à Y à tout les éléments selectionnés
     */
    public void symetrieY(){        
        for (ElementGeo element : dessin.getElements()) {
            if(element.isSelected())
            element.symetrieY(dessin.getOrigine());
        }
        notifyObserver(dessin);
    }
    /**
     * Efface l'element tampon
     */
    public void resetTampon(){
        dessin.setTempElement(null);
        notifyObserver(dessin);
    }
    /**
     * Groupe les éléments selectionnés
     */
    public void group(){
        List<ElementGeo> list = new ArrayList<ElementGeo>();
        for (ElementGeo element : dessin.getElements()) {
            if(element.isSelected())
            list.add(element);
        }
        if(!list.isEmpty()){
            Groupe group = new Groupe();
            for(ElementGeo element : list){
                group.getElements().add(element);
                dessin.getElements().remove(element);
            }
            dessin.getElements().add(group);
        notifyObserver(dessin);
        }
        
    }
    /**
     * Dégroupe les éléments sélectionnés
     */
    public void deGroup(){
        List<ElementGeo> list = new ArrayList<ElementGeo>();
        for (ElementGeo element : dessin.getElements()) {
            if(element.isSelected())
            list.add(element);
        }
        if(!list.isEmpty()){

            for(ElementGeo element : list){
                if(element instanceof Groupe){
                    for(ElementGeo elementGroup : ((Groupe)element).getElements()){
                        dessin.getElements().add(elementGroup);                        
                    }
                    dessin.getElements().remove(element);
                }
            }

        notifyObserver(dessin);
        }
    }
    /**
     * Supprime les éléments sélectionnés
     */
    public void delete(){
    List<ElementGeo> eleDel = new ArrayList<ElementGeo>();
         for(ElementGeo element : dessin.getElements()){
              if(element.isSelected())
                eleDel.add(element);
         }
         for (ElementGeo elementGeo : eleDel) {
                this.eraseElement(elementGeo);
         }
    }
    /**
     * Get dessin
     * @return dessin du model
     */
    public Dessin getDessin() {
        return dessin;
    }
    /**
     * Set dessin
     * @param dessin - dessin du model
     */
    public void setDessin(Dessin dessin) { 
        this.dessin = dessin; 
    }
     /**
     * Observateur des elements selectionnés
     * @return vrai s'il y a un element selectionné
     */
    public boolean isSelect(){
        boolean result=false;
        for (ElementGeo element : dessin.getElements()) {
            if(element.isSelected())
                result=true;
        }
        return result;
    }

    //**************************************************
    //		   IMPLÉMENTATION PATTERN OBSERVER
    //**************************************************

    /**
     * Ajouter un observer
     * @param obs - Observer
     */
    @Override
    public void addObserver(Observer obs) {
            this.listObserver.add(obs);
    }

    /**
     * Notifie les changement au observable
     * @param dessin - model mis à jour
     */
    @Override
    public void notifyObserver(Dessin dessin) {

            for(Observer obs : listObserver)
                    obs.update(dessin);
    }
    /**
     * Supprimer les observer 
     */
    @Override
    public void removeObserver() {
            listObserver = new ArrayList<Observer>();
    }
}
